#! /bin/sh
#
# This shell script benchmarks a program on a series of test problems
#

me=`echo "$0" | sed -e 's,.*/,,'`

usage="\
  Usage: $0 [OPTION] program

  -h, --help         print this help, then exit
  --verify           verify each transform before timing
  --verify-only      verify each transform but do not time
  --verify-tolerance set error tolerance for --verify
  --accuracy         run accuracy test
  --accuracy-rounds  set number of rounds for --accuracy
  -k, --keep-going   continue after verification error
  --time-min=X       set minimum measurement time
  --maxn=N           set maximum allowed problem size
  --maxnd=N          set maximum allowed multi-dimensional problem size
  -o=X, --user-option=X    undocumented
  "

help="
Try \`$me --help' for more information."

verify="no"
accuracy="no"
useropt=""
speed="yes"
maxn=1048576
maxnd=1048576
time_min=""
keep_going="no"
tolerance=""
rounds=""
arounds=""

for option
 do
  # If the previous option needs an argument, assign it.
 if test -n "$prev"; then
   eval "$prev=\$option"
   prev=
   shift
   continue
 fi

 optarg=`expr "x$option" : 'x[^=]*=\(.*\)'`

 case $option in

   --help | --h* | -h ) echo "$usage"; exit 0 ;;
   --keep-going | -k) keep_going=yes; shift;;
   --accuracy) accuracy=yes; speed=no; shift;;
   --verify) verify=yes; shift;;
   --verify-only) verify=yes; speed=no; shift;;
   --verify-tolerance) prev=tolerance; shift;;
   --verify-tolerance=*) tolerance=$optarg; shift;;
   --verify-rounds) prev=rounds; shift;;
   --verify-rounds=*) rounds=$optarg; shift;;
   --accuracy-rounds=*) arounds=$optarg; shift;;
   --time-min) prev=time_min; shift;;
   --time-min=*) time_min=$optarg; shift;;
   --maxn) prev=maxn; shift;;
   --maxnd) prev=maxnd; shift;;
   --maxn=*) maxn=$optarg; shift;;
   --maxnd=*) maxnd=$optarg; shift;;
   --user-option=* | -o=*) useropt="$useropt --user-option=$optarg"; shift;;
   -- ) break ;; # Stop option processing
   -* )
   echo "$me: invalid option $1$help"
   exit 1 ;;

   * )
   break ;;
 esac
done

if test -n "$prev"; then
  option=--`echo $prev | sed 's/_/-/g'`
  echo "$me: error: missing argument to $option" >&2
  exit 1
fi

case $# in
  0) echo "$me: missing argument$help" >&2
  exit 1;;
  1) ;;
  *) echo "$me: too many arguments$help" >&2
  exit 1;;
esac

program="$1"

SIZES_1D="2 4 6 8 9 12 15 16 18 24 32 36 64 80 108 128 210 256 504 512
1000 1024 1960 2048 4096 4725 8192 10368 16384 27000 32768 65536 75600
131072 165375 262144 362880 524288 1048576 1562500 2097152 3211264
4194304 6250000 8388608 12250000 16777216 25401600 33554432"

# large set of size including all sizes supported by cwplib
# SIZES_1D="1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 18 20 21 22 24 26 28
# 30 32 33 35 36 39 40 42 44 45 48 52 55 56 60 63 64 65 66 70 72 77 78
# 80 84 88 90 91 99 104 105 108 110 112 117 120 126 128 130 132 140 143
# 144 154 156 165 168 176 180 182 195 198 208 210 220 231 234 240 252
# 256 260 264 273 280 286 308 312 315 330 336 360 364 385 390 396 420
# 429 440 455 462 468 495 504 512 520 528 546 560 572 585 616 624 630
# 660 693 715 720 728 770 780 792 819 840 858 880 910 924 936 990 1000
# 1001 1008 1024 1040 1092 1144 1155 1170 1232 1260 1287 1320 1365 1386
# 1430 1456 1540 1560 1584 1638 1680 1716 1820 1848 1872 1960 1980 2002
# 2048 2145 2184 2288 2310 2340 2520 2574 2640 2730 2772 2860 3003 3080
# 3120 3276 3432 3465 3640 3696 3960 4004 4095 4096 4290 4368 4620 4680
# 4725 5005 5040 5148 5460 5544 5720 6006 6160 6435 6552 6864 6930 7280
# 7920 8008 8190 8192 8580 9009 9240 9360 10010 10296 10368 10920 11088
# 11440 12012 12870 13104 13860 15015 16016 16380 16384 17160 18018
# 18480 20020 20592 21840 24024 25740 27000 27720 30030 32760 32768
# 34320 36036 40040 45045 48048 51480 55440 60060 65520 65536 72072
# 75600 80080 90090 102960 120120 131072 144144 165375 180180 240240
# 262144 360360 362880 524288 720720 1048576 2097152 4194304 8388608
# 16777216 33554432"

SIZES_2D="4x4 5x5 6x6 7x7 8x8 4x8 8x4 9x9 10x10 11x11 12x12 13x13
14x14 15x15 16x16 25x24 32x32 48x48 49x49 60x60 72x56 64x64 75x75
80x80 84x84 128x64 16x512 96x96 100x100 105x105 112x112 120x120
128x128 144x144 180x180 512x64 256x128 240x240 256x256 64x1024 360x360
512x512 1000x1000 1024x1024 1050x1050 1458x1458 1960x1960 2048x2048
2916x2916 4096x4096 4116x4116 5832x5832 8192x8192 8400x8400
10368x10368 16384x16384 16464x16464 23328x23328 32768x32768
32805x32805"

SIZES_3D="4x4x4 5x5x5 6x6x6 7x7x7 8x8x8 9x9x9 10x10x10 11x11x11
12x12x12 13x13x13 14x14x14 15x15x15 16x16x16 4x8x16 24x25x28 32x32x32
48x48x48 49x49x49 60x60x60 72x60x56 64x64x64 75x75x75 80x80x80
256x64x32 84x84x84 96x96x96 100x100x100 16x1024x64 105x105x105
112x112x112 120x120x120 128x128x128 144x144x144 512x128x64 180x180x180
256x128x256 210x210x210 256x256x256 270x270x270 512x64x1024
324x324x324 420x420x420 512x512x512 525x525x525 648x648x648
840x840x840 1024x1024x1024 1029x1029x1029"

DIRECTIONS="f b"
PLACE="i o"
REALITY="c r"
ALL_SIZES="$SIZES_1D $SIZES_2D $SIZES_3D"

if test ! -x "$program"; then
  echo "``$program'' is not executable!" >&2
  exit 1
fi

test "$speed" = "no" || test -n "$time_min" || time_min=`$program --print-time-min`
precision=`$program --print-precision`

# shorten the name
case $precision in
  single) precision=s;;
  double) precision=d;;
esac

name=`$program --info name`
test -z "$tolerance" || tolerance="--verify-tolerance $tolerance"
test -z "$rounds" || rounds="--verify-rounds $rounds"
test -z "$arounds" || arounds="--accuracy-rounds $arounds"
vflags="$tolerance $rounds $useropt"
aflags="$arounds"

for place in $PLACE; do
  for reality in $REALITY; do
    for size in $ALL_SIZES; do
      case $size in
        *x*) curmaxn=$maxnd ;;
        *) curmaxn=$maxn ;;
      esac
      s=`echo $size | sed -e "s/x/ '*' /g"`
      if test `eval "expr $s"` -gt $curmaxn; then
	continue
      fi

      case $size in
	*x*) oned=no;;
	*)   oned=yes;;
      esac

      for dir in $DIRECTIONS; do
	problem=${place}${reality}${dir}${size}
	doable=`$program $useropt --can-do $problem`
	if test "$doable" = "#t"; then
	  print="yes"
	  if test "$verify" = "yes"; then
	    acc=`$program $vflags --verbose --verify $problem | tail -n 1`||
	    { acc="FAILED FAILED FAILED"; 
	      test "$keep_going" = "yes" || exit 1; }
	  else
	    acc=""
	  fi

	  if test "$speed" = yes; then
	    time="`$program $useropt --report-benchmark --time-min $time_min --speed $problem | tail -n 1` " || 
	    time="FAILED FAILED"
	    if test "x$time" = "x "; then time="FAILED FAILED"; fi
	  else
	    time=""
	  fi

	  if test "$accuracy" = "yes"; then
	    if test "$oned" = "yes"; then
	       acc=`$program $useropt $aflags --accuracy $problem | tail -n 1`
	    else
	       print="no"
	    fi
	  fi

	  if test "$print" = "yes"; then
	    echo "${name} ${precision}${reality}${place}${dir} ${size} ${time}${acc}"
	  fi
	fi
      done
    done
  done
done


